package shark.scheduler.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import shark.scheduler.model.Lock;

import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class DistributedLockHandler {
    private final static long LOCK_EXPIRE = 10 * 1000L;// 单个业务持有锁的时间30s，防止死锁
    private final static long LOCK_TRY_INTERVAL = 30L;// 默认30ms尝试一次
    private final static long LOCK_TRY_TIMEOUT = 20 * 1000L;// 默认尝试20

    @Autowired
    private StringRedisTemplate template;

    /**
     * 尝试获取全局锁
     *
     * @param lock 锁的名称
     * @return true 获取成功，false获取失败
     */
    public boolean tryLock(Lock lock) {
        return getLock(lock, LOCK_EXPIRE);
    }



    /**
     * 尝试获取全局锁
     *
     * @param lock 锁的名称
     * @param lockExpireTime 锁的过期
     * @return true 获取成功，false获取失败
     */
    public boolean tryLock(Lock lock, long lockExpireTime) {
        return getLock(lock, lockExpireTime);
    }

    /**
     * 操作redis获取全局锁
     *
     * @param lock 锁的名称
     * @param lockExpireTime 获取成功后锁的过期时间
     * @return true 获取成功，false获取失败
     */
    public boolean getLock(Lock lock, long lockExpireTime) {
        try {
            if (StringUtils.isEmpty(lock.getName()) || StringUtils.isEmpty(lock.getValue())) {
                return false;
            }

            boolean isSuccess = template.opsForValue().setIfAbsent(lock.getName(), lock.getValue());
            if (isSuccess) {
                //设置分布式锁的过期时间
                template.expire(lock.getName(), lockExpireTime, TimeUnit.SECONDS);
                return true;
            }else {// 存在锁
                log.error(System.currentTimeMillis()+"---lock is exist!");
                return false;
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }

    /**
     * 释放锁
     */
    public void releaseLock(Lock lock) {
        if (!StringUtils.isEmpty(lock.getName())) {
            template.delete(lock.getName());
        }
    }
}
